﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;

namespace Teal.Compiler {

    /// <summary>
    /// 提供语义解析使用的辅助函数。
    /// </summary>
    public static partial class ResolveHelper {

        /// <summary>
        /// 对指定的方法组进行调用，返回代表计算结果的表达式。
        /// </summary>
        /// <param name="context">包含所有解析状态的上下文对象。</param>
        /// <param name="methods">要调用的方法组。</param>
        /// <param name="instance">当前的实例对象。如果不存在则为 null。</param>
        /// <param name="arguments">调用的参数。</param>
        /// <param name="srcNode">引发本次操作的原始语法树节点，主要用于报错时提示正确的位置。</param>
        /// <returns>返回代表计算结果的表达式。如果解析出现错误则返回 null 。</returns>
        public static ResolvedMethodInvocationExpression invoke(ResolveContext context, MemberReferenceGroup methods, Expression instance, FuncCallExpression.Argument arguments, Node srcNode) {

            // 解析参数。
            var resolvedArguments = resolveArguments(context, arguments);
            if (resolvedArguments == null) {
                return null;
            }

            // 创建临时列表。
            var results = ListObjectPool<ArgumentsMatchResult>.alloc(methods.Count);

            // 找出所有匹配项中最好的重载。
            int foundBest = resolveMethodOverload(context, methods, resolvedArguments, results);

            ResolvedMethodInvocationExpression result;

            if (foundBest < 0) {
                reportResolveMethodOverloadError(results, srcNode);
                result = null;
            } else {

                var method = results[foundBest].member;

                // 检查实例。
                if (method.memberType != MemberType.constructor) {
                    ResolveHelper.checkInstance(method, context, ref instance, srcNode);
                }

                // 检查泛型约束。
                if (method is GenericMethodReference) {
                    ((GenericMethodReference)method).checkConstraints();
                }

                result = new ResolvedMethodInvocationExpression() {
                    instance = instance,
                    target = method,
                    arguments = applyArguments(context, results[foundBest], resolvedArguments)
                };
            }

            // 释放相关对象。
            foreach (var c in results) {
                ArgumentsMatchResult.free(c);
            }
            ListObjectPool<ArgumentsMatchResult>.free(results);
            ResolvedArguments.free(resolvedArguments);

            return result;

        }

        /// <summary>
        /// 对指定的方法进行调用，返回代表计算结果的表达式。
        /// </summary>
        /// <param name="context">包含所有解析状态的上下文对象。</param>
        /// <param name="method">要调用的方法。</param>
        /// <param name="instance">当前的实例对象。如果不存在则为 null。</param>
        /// <param name="arguments">调用的参数。</param>
        /// <param name="srcNode">引发本次操作的原始语法树节点，主要用于报错时提示正确的位置。</param>
        /// <returns>返回代表计算结果的表达式。如果解析出现错误则返回 null 。</returns>
        public static ResolvedMethodInvocationExpression invoke(ResolveContext context, MethodReference method, Expression instance, FuncCallExpression.Argument arguments, Node srcNode) {

            // 检查实例。
            if (method.memberType != MemberType.constructor) {
                ResolveHelper.checkInstance(method, context, ref instance, srcNode);
            }

            // 检查泛型约束。
            method.checkConstraints();

            // 解析参数。
            var resolvedArguments = resolveArguments(context, arguments);
            if (resolvedArguments == null) {
                return null;
            }

            ResolvedMethodInvocationExpression result;

            // 检查参数的匹配度。
            var matchResult = matchArguments(context, method, resolvedArguments);
            if (!matchResult.isValid) {
                reportResolveMethodOverloadError(matchResult, resolvedArguments, srcNode);
                result = null;
            } else {
                result = new ResolvedMethodInvocationExpression() {
                    instance = instance,
                    target = matchResult.member,
                    arguments = applyArguments(context, matchResult, resolvedArguments)
                };
            }

            ArgumentsMatchResult.free(matchResult);
            ResolvedArguments.free(resolvedArguments);

            return result;

        }

        /// <summary>
        /// 调用指定的表达式所表示的函数，返回代表计算结果的表达式。
        /// </summary>
        /// <param name="context">包含所有解析状态的上下文对象。</param>
        /// <param name="expression">要调用的表达式。</param>
        /// <param name="arguments">调用的参数。</param>
        /// <param name="srcNode">引发本次操作的原始语法树节点，主要用于报错时提示正确的位置。</param>
        /// <returns>返回代表计算结果的表达式。如果解析出现错误则返回 null 。</returns>
        public static ResolvedFunctionInvocationExpression invoke(ResolveContext context, Expression expression, FuncCallExpression.Argument arguments, Node srcNode) {
            if (expression == null) {
                return null;
            }

            // 确保目标表达式是函数类型。
            var funcType = expression.resolvedType;
            if (funcType.underlyingType != PredefinedTypes.System_Func_T) {
                ResolvedArguments.free(resolveArguments(context, arguments));
                Compiler.error(ErrorCode.none, "无法调用目标表达式；表达式不是函数类型", srcNode);
                return null;
            }

            var resolvedArguments = resolveArguments(context, arguments);
            if (resolvedArguments == null) {
                return null;
            }

            // 直接调用表达式时无法使用命名参数。
            if (resolvedArguments.namedArgumentsCount > 0) {
                Compiler.error(ErrorCode.none, "无法在当前上下文使用命名参数", resolvedArguments[resolvedArguments.positionalArgumentsCount].name);
                return null;
            }

            Expression[] args = new Expression[resolvedArguments.count];
            bool hasError = false;

            // 验证每个实参都能转为形参类型。
            for (var i = 0; i < resolvedArguments.count; i++) {

                // 参数太多
                if (i + 1 >= funcType.genericArguments.Length) {
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”函数；调用的参数太多", funcType.fullName), resolvedArguments[i].value);
                    return null;
                }

                var argument = resolvedArguments[i];
                var parameterType = funcType.genericArguments[i + 1];

                // 处理特殊参数。
                switch (arguments.type) {
                    case FuncCallExpression.ArgumentType.@in:
                        if (parameterType.underlyingType == PredefinedTypes.System_Func_Out_T) {
                            Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”函数；参数 {1} 是输出参数；应输入“out”", funcType.fullName, i + 1), argument.value);
                            hasError = true;
                        } else if (parameterType.underlyingType == PredefinedTypes.System_Func_Ref_T) {
                            Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”函数；参数 {1} 是引用参数；应输入“ref”", funcType.fullName, i + 1), argument.value);
                            hasError = true;
                        } else {
                            args[i] = ResolveHelper.convertTo(arguments.resolvedValue, parameterType, State.unset, argument.value);
                            if (args[i] == null) {
                                hasError = true;
                            }
                        }

                        break;
                    case FuncCallExpression.ArgumentType.@out:
                    case FuncCallExpression.ArgumentType.outAssignTo:
                        if (parameterType.underlyingType != PredefinedTypes.System_Func_Out_T) {
                            Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”函数；参数 {1} 不是输出参数；应删除“out”", funcType.fullName, i + 1), argument.value);
                            hasError = true;
                        }
                        args[i] = arguments.resolvedValue;
                        break;
                    case FuncCallExpression.ArgumentType.@ref:
                        if (parameterType.underlyingType != PredefinedTypes.System_Func_Ref_T) {
                            Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”函数；参数 {1} 不是引用参数；应删除“out”", funcType.fullName, i + 1), argument.value);
                            hasError = true;
                        }
                        args[i] = arguments.resolvedValue;
                        break;
                }

            }

            if (hasError) {
                return null;
            }

            return new ResolvedFunctionInvocationExpression() {
                target = expression,
                arguments = args,
            };

        }

        /// <summary>
        /// 解析双目运算符重载。
        /// </summary>
        /// <param name="members">所有可用的函数。</param>
        /// <param name="arguments">提供的参数。</param>
        /// <param name="srcNode">引发本次操作的源节点，主要用于报错。</param>
        /// <returns>返回匹配的成员，如果无匹配，则返回 null 。</returns>
        public static ResolvedMethodInvocationExpression invoke(ResolveContext context, Expression left, TokenType @operator, Expression right, Node srcNode) {

            string opName = "@" + @operator.getName();

            // 创建临时列表。
            List<ArgumentsMatchResult> results = ListObjectPool<ArgumentsMatchResult>.alloc();

            try {

                ResolvedArguments leftArguments = new ResolvedArguments();
                int leftOk = resolveOperatorOverload(context, left, opName, right, leftArguments, results);
                ResolvedArguments rightArguments = new ResolvedArguments();
                int rightOk = resolveOperatorOverload(context, right, opName, left, rightArguments, results);

                // 向用户报告错误。
                if (results.Count == 0) {
                    Compiler.error(ErrorCode.none, String.Format("“{1}”和“{2}”之间不存在“{0}”运算符重载", @operator.getName(), left.resolvedType.fullName, right.resolvedType.fullName), srcNode);
                } else if (results.Count == 1) {
                    return new ResolvedMethodInvocationExpression() {
                        target = results[0].member,
                        // arguments2 = leftOk != -1 ? leftArguments : rightArguments,
                        instance = leftOk != -1 ? left : right
                    };
                } else {
                    reportResolveMethodOverloadError(results, srcNode);
                }

            } finally {

                // 释放结果对象。
                foreach (var c in results) {
                    ArgumentsMatchResult.free(c);
                }
                ListObjectPool<ArgumentsMatchResult>.free(results);

            }

            return null;

        }

        /// <summary>
        /// 解析单目运算符重载。
        /// </summary>
        /// <param name="members">所有可用的函数。</param>
        /// <param name="arguments">提供的参数。</param>
        /// <param name="srcNode">引发本次操作的源节点，主要用于报错。</param>
        /// <returns>返回匹配的成员，如果无匹配，则返回 null 。</returns>
        public static ResolvedMethodInvocationExpression invoke(ResolveContext context, TokenType @operator, Expression value, Node srcNode) {
            string operatorName = @operator.getName();
            var ops = value.resolvedType.getMember("@" + operatorName);
            if (ops == null) {
                Compiler.error(ErrorCode.none, String.Format("“{0}”不存在“{1}”操作符重载", value.resolvedType.fullName, operatorName), srcNode);
                return null;
            }
            return new ResolvedMethodInvocationExpression() {
                instance = value,
                target = (MethodReference)ops
            };
        }

        /// <summary>
        /// 表示解析后的函数调用参数列表。
        /// </summary>
        private sealed class ResolvedArguments {

            #region 对象池

            static ResolvedArguments[] _objectPool = new ResolvedArguments[128];
            static int _objectPoolLength;

            /// <summary>
            /// 当对象池中申请一个新的对象。
            /// </summary>
            /// <param name="capicity"></param>
            /// <returns></returns>
            public static ResolvedArguments alloc() {
                if (_objectPoolLength == 0) {
                    return new ResolvedArguments();
                }
                return _objectPool[_objectPoolLength--];
            }

            /// <summary>
            /// 将指定的对象放入对象池。
            /// </summary>
            /// <param name="capicity"></param>
            /// <returns></returns>
            public static void free(ResolvedArguments value) {
                if (_objectPoolLength < _objectPool.Length) {
                    value.positionalArgumentsCount = value.namedArgumentsCount = 0;
                    _objectPool[++_objectPoolLength] = value;
                }
            }

            #endregion

            /// <summary>
            /// 获取或设置当前参数的具体值。
            /// </summary>
            FuncCallExpression.Argument[] _values = new FuncCallExpression.Argument[4];

            /// <summary>
            /// 获取当前参数列表中位置参数的个数。
            /// </summary>
            public int positionalArgumentsCount = 0;

            /// <summary>
            /// 获取当前参数列表中命名参数个数。
            /// </summary>
            public int namedArgumentsCount = 0;

            /// <summary>
            /// 获取指定索引的参数。
            /// </summary>
            /// <param name="index"></param>
            /// <returns></returns>
            public FuncCallExpression.Argument this[int index] {
                get {
                    return _values[index];
                }
                set {
                    _values[index] = value;
                }
            }

            /// <summary>
            /// 获取当前调用的全部参数个数。
            /// </summary>
            public int count {
                get {
                    return positionalArgumentsCount + namedArgumentsCount;
                }
            }

            /// <summary>
            /// 确保当前参数列表容器足够大。
            /// </summary>
            public void ensureCapicity() {
                var c = count;
                if (_values.Length < c) {
                    _values = new FuncCallExpression.Argument[c];
                }
            }

            /// <summary>
            /// 将当前节点写入指定的 <see cref="IndentedTextWriter" /> 对象。
            /// </summary>
            /// <param name="writer">写入的目标对象。</param>
            public void write(IndentedTextWriter writer) {
                writer.Write('(');
                for (int i = 0; i < count; i++) {

                }
                writer.Write(')');
            }

        }

        /// <summary>
        /// 解析指定的参数。
        /// </summary>
        /// <param name="context">用于存储所有解析信息的上下文对象。</param>
        /// <param name="arguments">要解析的原始参数。</param>
        /// <returns>返回解析后的函数调用参数列表。</returns>
        private static ResolvedArguments resolveArguments(ResolveContext context, FuncCallExpression.Argument arguments) {

            var foundError = false;
            var result = ResolvedArguments.alloc();
            for (var argument = arguments; argument != null; argument = argument.next) {

                // 解析命名参数。
                if (argument.name != null) {
                    result.namedArgumentsCount++;
                } else {
                    if (result.namedArgumentsCount > 0) {
                        Compiler.error(ErrorCode.none, "非命名参数必须出现在其它命名参数的前面", argument);
                        foundError = true;
                    }
                    result.positionalArgumentsCount++;
                }

                // 解析参数值。
                SymbolUsage symbolUsage;
                switch (argument.type) {
                    case FuncCallExpression.ArgumentType.@in:
                        symbolUsage = SymbolUsage.argument;
                        break;
                    case FuncCallExpression.ArgumentType.@ref:
                        symbolUsage = SymbolUsage.getSetValue;
                        break;
                    case FuncCallExpression.ArgumentType.@out:
                        symbolUsage = SymbolUsage.setValue;
                        break;
                    case FuncCallExpression.ArgumentType.outAssignTo:
                    default:
                        symbolUsage = SymbolUsage.define;
                        break;
                }

                Expression instance;
                ISymbol argumentSymbol = argument.value.resolveAsSymbol(context, symbolUsage, out instance);
                if (argumentSymbol == null) {
                    foundError = true;
                    continue;
                }

                if (symbolUsage == SymbolUsage.argument) {

                    // 方法组需要特殊解析。
                    if (argumentSymbol is MemberReferenceGroup) {
                        argument.resolvedValue = new ResolvedMethodReferenceGroupExpression() {
                            target = (MemberReferenceGroup)argumentSymbol,
                            instance = instance
                        };
                    } else if (argumentSymbol == Expression.empty) {
                        argument.resolvedValue = instance;
                    } else {
                        argument.resolvedValue = argumentSymbol.getValue(context, instance, argument.value);
                    }

                } else {
                    argument.resolvedValue = argumentSymbol.addressOf(context, instance, argument.value);
                }

                if (argument.resolvedValue == null) {
                    foundError = true;
                }

            }

            if (foundError) {
                ResolvedArguments.free(result);
                return null;
            }

            result.ensureCapicity();

            int i = 0;
            for (var argument = arguments; argument != null; argument = argument.next) {
                result[i++] = argument;
            }

            return result;
        }

        /// <summary>
        /// 表示一个成员形参和实参的匹配结果。
        /// </summary>
        [DebuggerDisplay("{member.fullName}=>{type}")]
        private sealed class ArgumentsMatchResult {

            #region 对象池

            static ArgumentsMatchResult[] _objectPool = new ArgumentsMatchResult[128];
            static int _objectPoolLength;

            /// <summary>
            /// 当对象池中申请一个新的对象。
            /// </summary>
            /// <param name="capicity"></param>
            /// <returns></returns>
            public static ArgumentsMatchResult alloc() {
                if (_objectPoolLength == 0) {
                    return new ArgumentsMatchResult();
                }
                return _objectPool[_objectPoolLength--];
            }

            /// <summary>
            /// 将指定的对象放入对象池。
            /// </summary>
            /// <param name="capicity"></param>
            /// <returns></returns>
            public static void free(ArgumentsMatchResult value) {
                if (_objectPoolLength < _objectPool.Length) {
                    value.argumentToParameterMap.Clear();
                    value.conversions.Clear();
                    value.type = ArgumentsMatchType.none;
                    value.compareState = ArgumentCompareResultType.best;
                    _objectPool[++_objectPoolLength] = value;
                }
            }

            #endregion

            /// <summary>
            /// 获取当前结果对应的成员。
            /// </summary>
            public MemberReference member;

            /// <summary>
            /// 获取当前结果对应的形参。
            /// </summary>
            public ParameterReference[] parameters;

            /// <summary>
            /// 获取当前参数数目的基本匹配结果。
            /// </summary>
            public ArgumentsMatchType type;

            /// <summary>
            /// 判断当前匹配是否是合法的。
            /// </summary>
            public bool isValid {
                get {
                    return type >= ArgumentsMatchType.VALID;
                }
            }

            /// <summary>
            /// 导致参数无法匹配的参数索引。
            /// </summary>
            public int badArgumentIndex;

            /// <summary>
            /// 获取或设置当前结果和其它结果比较的状态。
            /// </summary>
            public ArgumentCompareResultType compareState;

            /// <summary>
            /// 获取存储实参对应的实际形参的索引。如果实参与形参一一对应，则为空集合 。
            /// </summary>
            public List<int> argumentToParameterMap = new List<int>();

            /// <summary>
            /// 获取存储每个实参到相应形参使用的类型转换类型。
            /// </summary>
            public List<ConversionType> conversions = new List<ConversionType>();

            /// <summary>
            /// 获取指定实参索引实际匹配的形参。
            /// </summary>
            /// <param name="argumentIndex"></param>
            /// <returns></returns>
            public ParameterReference getParameter(int argumentIndex) {
                return parameters[getParameterIndex(argumentIndex)];
            }

            /// <summary>
            /// 获取指定实参索引实际匹配的形参类型。
            /// </summary>
            /// <param name="argumentIndex">要获取的实参索引。</param>
            /// <returns></returns>
            public TypeReference getParameterType(int argumentIndex) {
                if (type == ArgumentsMatchType.applicableInArgListExpandedForm) {
                    if (argumentIndex >= parameters.Length) {
                        return parameters[parameters.Length - 1].type.genericArguments[0];
                    }
                }
                return getParameter(argumentIndex).type;
            }

            /// <summary>
            /// 获取指定实参索引实际匹配的形参索引。
            /// </summary>
            /// <param name="argumentIndex">要获取的实参索引。</param>
            /// <returns></returns>
            public int getParameterIndex(int argumentIndex) {
                return argumentToParameterMap.Count > 0 ? argumentToParameterMap[argumentIndex] : argumentIndex;
            }

        }

        /// <summary>
        /// 表示参数匹配结果类型。
        /// </summary>
        private enum ArgumentsMatchType {

            /// <summary>
            /// 未判断匹配结果。
            /// </summary>
            none,

            /// <summary>
            /// 找不到指定的命名参数。
            /// </summary>
            namedArgumentNotFound,

            /// <summary>
            /// 未提供指定的必选参数。
            /// </summary>
            missingArgument,

            /// <summary>
            /// 由于参数类型不匹配导致不匹配。
            /// </summary>
            badArgument,

            /// <summary>
            /// 提供的参数过多。
            /// </summary>
            tooManyArguments,

            /// <summary>
            /// 命名参数和位置参数冲突。
            /// </summary>
            nameUsedForPositional,

            /// <summary>
            /// 重复的命名参数。
            /// </summary>
            dumpNamedArgument,

            /// <summary>
            /// 泛型形参类型无法推导。
            /// </summary>
            genericTypeParameterUnknown,

            /// <summary>
            /// 标记当前结果是合法的。
            /// </summary>
            VALID,

            /// <summary>
            /// 以展开参数列表形式匹配。
            /// </summary>
            applicableInArgListExpandedForm,

            /// <summary>
            /// 以展开可选参数形式匹配。
            /// </summary>
            applicableInOptionalExpandedForm,

            /// <summary>
            /// 以普通形式匹配。
            /// </summary>
            applicableInNormalForm,

        }

        /// <summary>
        /// 表示重载比较结果类类型。
        /// </summary>
        private enum ArgumentCompareResultType {

            /// <summary>
            /// 当前成员是最佳匹配。
            /// </summary>
            best,

            /// <summary>
            /// 存在比当前成员更好的重载。
            /// </summary>
            notBest,

            /// <summary>
            /// 存在比当前成员更差的重载。
            /// </summary>
            notWorst,

            /// <summary>
            /// 最差的匹配。
            /// </summary>
            worst,

        }

        private static Expression[] applyArguments(ResolveContext context, ArgumentsMatchResult result, ResolvedArguments arguments) {
            Expression[] actualArguments = new Expression[arguments.count];
            for (int i = 0; i < arguments.count; i++) {
                var argument = arguments[i];
                if (argument.resolvedValue.resolvedType == null) {
                    argument.resolvedValue = argument.resolvedValue.resolveAsValue(context, result.getParameterType(i), State.unset);
                }
                actualArguments[result.getParameterIndex(i)] = argument.resolvedValue;
            }

            return actualArguments;
        }

        /// <summary>
        /// 解析方法组内每个方法和指定的参数，并将每个方法的匹配结果放入集合。
        /// </summary>
        /// <param name="methods"></param>
        /// <param name="arguments"></param>
        /// <param name="matchResults"></param>
        /// <returns></returns>
        private static int resolveMethodOverload(ResolveContext context, MemberReferenceGroup methods, ResolvedArguments arguments, List<ArgumentsMatchResult> matchResults) {

            // 初步匹配所有函数的参数匹配情况。
            foreach (var method in methods) {
                matchResults.Add(matchArguments(context, method, arguments));
            }

            // 依次比较函数，找到最匹配的重载。
            int foundBest = -1;

            for (int i = 0; i < matchResults.Count; i++) {
                var result = matchResults[i];

                // 如果参数本身就不匹配，则不需要处理。
                // 如果当前为 notBest, 说明肯定不是 best。
                if (!result.isValid || result.compareState == ArgumentCompareResultType.notBest) {
                    continue;
                }

                // 和其它所有重载比较，确认当前匹配是否是最佳匹配。
                bool isBest = true;
                for (int j = 0; j < matchResults.Count; j++) {
                    var result2 = matchResults[j];

                    if (i == j || !result2.isValid) {
                        continue;
                    }

                    var better = betterFunction(result, result2, arguments);
                    if (better == BetterResult.left) {
                        result2.compareState = ArgumentCompareResultType.notBest;
                    } else {
                        isBest = false;
                        if (better == BetterResult.right) {
                            result.compareState = ArgumentCompareResultType.notBest;
                        }
                    }
                }

                // 更新比较结果。
                if (result.compareState == ArgumentCompareResultType.worst) {
                    result.compareState = isBest ? ArgumentCompareResultType.best : ArgumentCompareResultType.notWorst;
                }

                if (isBest) {
                    foundBest = i;
                }

            }

            return foundBest;

        }

        /// <summary>
        /// 返回指定的方法对指定参数的匹配结果。
        /// </summary>
        /// <param name="member"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        private static ArgumentsMatchResult matchArguments(ResolveContext context, MemberReference member, ResolvedArguments arguments) {

            // 初始化新对象。由于此次使用的对象池，目标对象可能已赋值。
            ArgumentsMatchResult result = ArgumentsMatchResult.alloc();
            result.member = member;

            var method = member as MethodReference;
            if (method != null) {
                result.parameters = method.parameters;
            } else {
                var indexer = member as IndexerReference;
                if (indexer != null) {
                    result.parameters = method.parameters;
                } else {
                    throw new Unreachable();
                }
            }

            int parameterCount = result.parameters.Length;
            int argumentsCount = arguments.count;

            // 处理命名参数。
            if (arguments.namedArgumentsCount > 0) {

                // 存在命名参数，则一个形参最多对应一个形参，params 参数无法展开，
                // 因此有命名参数时，实参个数不能大于形参个数。
                if (argumentsCount > parameterCount) {
                    result.badArgumentIndex = parameterCount;
                    result.type = ArgumentsMatchType.namedArgumentNotFound;
                    return result;
                }

                // 设置参数重排列表。

                // 处理位置参数。
                for (int i = 0; i < arguments.positionalArgumentsCount; i++) {
                    result.argumentToParameterMap.Add(i);
                }

                // 处理命名参数。
                for (int i = arguments.positionalArgumentsCount; i < argumentsCount; i++) {
                    result.argumentToParameterMap.Add(-1);
                }

                // 搜索命名参数的实际位置，并依次填入参数数组。
                for (int i = arguments.positionalArgumentsCount; i < argumentsCount; i++) {
                    string argumentName = arguments[i].name.value;

                    // 查找当前命名参数对应的实参索引。
                    for (int j = 0; j < parameterCount; j++) {
                        if (method.parameters[j].name == argumentName) {

                            // argumentToParameterMap 如果不是 -1，说明之前已经使用了此位置参数。
                            if (result.argumentToParameterMap[i] != -1) {
                                result.type = j < arguments.positionalArgumentsCount ? ArgumentsMatchType.nameUsedForPositional : ArgumentsMatchType.dumpNamedArgument;
                                result.badArgumentIndex = i;
                                return result;
                            }

                            result.argumentToParameterMap[i] = j;

                            // 继续处理下一个参数。
                            goto foundParamter;
                        }
                    }

                    // 找不到符合名字的参数列表。
                    result.type = ArgumentsMatchType.namedArgumentNotFound;
                    result.badArgumentIndex = i;
                    return result;

                foundParamter:
                    ;
                }

                // 确保其它未提供的参数必须都是可选参数。
                for (int i = 0; i < parameterCount; i++) {
                    if (result.argumentToParameterMap[i] < 0) {
                        if (method.parameters[i].isOptional) {
                            result.type = ArgumentsMatchType.missingArgument;
                            result.badArgumentIndex = i;
                            return result;
                        }

                        // 可选参数后一定是可选参数，不需要继续处理。
                        break;
                    }
                }

            }

            // 尝试以正常形式匹配。
            if (argumentsCount == parameterCount && matchArgumentsType(result, arguments, argumentsCount)) {
                result.type = ArgumentsMatchType.applicableInNormalForm;
                return result;
            }

            // 尝试以展开缺省参数形式匹配。
            if (argumentsCount < parameterCount) {

                // 缺少的参数一定是可选参数。
                if (!result.parameters[argumentsCount].isOptional) {
                    result.badArgumentIndex = argumentsCount;
                    result.type = ArgumentsMatchType.missingArgument;
                    return result;
                }

                // 检查参数匹配程度。
                if (matchArgumentsType(result, arguments, argumentsCount)) {
                    result.type = ArgumentsMatchType.applicableInOptionalExpandedForm;
                }
                return result;
            }

            // 尝试以展开 params 形式匹配。
            if (parameterCount > 0) {

                // 最后一个参数一定是 params 参数。
                var lastParam = result.parameters[parameterCount - 1];
                if (lastParam.isParams) {

                    // 检查除了 params 以外其它参数是否都匹配。
                    if (!matchArgumentsType(result, arguments, parameterCount - 1)) {
                        return result;
                    }

                    // 检查每个 params 参数是否都可以转为目标类型。
                    if (lastParam.parameterType == VariableType.argListParameter) {
                        result.type = ArgumentsMatchType.applicableInArgListExpandedForm;
                        return result;
                    }

                    // 将多个 params 封装为新的数组。
                    var paramElementType = lastParam.type.genericArguments[0];

                    // 检查之后参数的匹配。
                    for (int i = parameterCount; i < argumentsCount; i++) {
                        var conversion = arguments[i].resolvedValue.classifyConversion(paramElementType);
                        result.conversions.Add(conversion);
                        if (conversion == ConversionType.none || conversion > ConversionType.IMPILICT) {
                            result.type = ArgumentsMatchType.badArgument;
                            result.badArgumentIndex = i;
                            return result;
                        }
                    }

                    result.type = ArgumentsMatchType.applicableInArgListExpandedForm;
                    return result;
                }
            }

            if (argumentsCount > parameterCount) {
                result.type = ArgumentsMatchType.tooManyArguments;
                result.badArgumentIndex = parameterCount;
            }
            return result;

        }

        /// <summary>
        /// 检查每个实参类型是否都可转为形参类型。
        /// </summary>
        /// <param name="matchResult">存储当前参数匹配结果的对象。</param>
        /// <param name="arguments">要检查的实参。</param>
        /// <param name="argumentsCount">检查的实参个数。</param>
        private static bool matchArgumentsType(ArgumentsMatchResult matchResult, ResolvedArguments arguments, int argumentsCount) {

            // 尝试推导泛型形参。
            if (!inflateGenericParamters(matchResult, arguments, argumentsCount)) {
                return false;
            }

            for (var i = 0; i < argumentsCount; i++) {
                var argument = arguments[i];
                var parameter = matchResult.getParameter(i);

                // 形参和实参的参数修饰符必须一致。
                switch (argument.type) {
                    case FuncCallExpression.ArgumentType.@in:
                        if (parameter.isOutOrRef) {
                            goto default;
                        }
                        break;
                    case FuncCallExpression.ArgumentType.@out:
                    case FuncCallExpression.ArgumentType.outAssignTo:
                        if (parameter.parameterType != VariableType.outParameter) {
                            goto default;
                        }
                        // fn(out=>a)
                        if (arguments[i].resolvedValue.resolvedType == PredefinedTypes.var) {
                            continue;
                        }
                        break;
                    case FuncCallExpression.ArgumentType.@ref:
                        if (parameter.parameterType != VariableType.refParameter) {
                            goto default;
                        }
                        break;
                    default:
                        matchResult.type = ArgumentsMatchType.badArgument;
                        matchResult.badArgumentIndex = i;
                        return false;
                }

                // 形参必须可以转到实参。
                ConversionType conversion = argument.resolvedValue.classifyConversion(parameter.type);
                matchResult.conversions.Add(conversion);
                if (conversion == ConversionType.none || conversion > ConversionType.IMPILICT) {
                    matchResult.type = ArgumentsMatchType.badArgument;
                    matchResult.badArgumentIndex = i;
                    return false;
                }

            }

            return true;

        }

        /// <summary>
        /// 尝试推断泛型形参。
        /// </summary>
        /// <param name="matchResult"></param>
        /// <param name="arguments"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        private static bool inflateGenericParamters(ArgumentsMatchResult matchResult, ResolvedArguments arguments, int count) {

            // 不是泛型无需推导。
            if (matchResult.member.genericParameters == null) {
                return true;
            }

            int leftInflatedTypeCount = matchResult.member.genericParameters.Length;
            TypeReference[] inflatedTypes = new TypeReference[leftInflatedTypeCount];

            for (var i = 0; i < count; i++) {
                var argument = arguments[i];
                var parameter = matchResult.getParameter(i);
                tryInflateGenericParamter(matchResult, argument.resolvedValue.resolvedType, parameter.type, inflatedTypes, ref leftInflatedTypeCount);
            }

            // 可能包含 params 参数。
            if (arguments.count > count && count > 0) {
                var parameter = matchResult.getParameter(count - 1);
                for (var i = count; i < arguments.count; i++) {
                    var argument = arguments[i];
                    tryInflateGenericParamter(matchResult, argument.resolvedValue.resolvedType, parameter.type, inflatedTypes, ref leftInflatedTypeCount);
                }
            }

            if (leftInflatedTypeCount > 0) {
                matchResult.type = ArgumentsMatchType.genericTypeParameterUnknown;
                for (var i = 0; i < inflatedTypes.Length; i++) {
                    if (inflatedTypes[i] == null) {
                        matchResult.badArgumentIndex = i;
                        break;
                    }
                }
                return false;
            }

            var method = ((GenericMethodDefinitionReference)matchResult.member).makeGenericMethod(inflatedTypes);
            matchResult.member = method;
            matchResult.parameters = method.parameters;
            return true;
        }

        private static void tryInflateGenericParamter(ArgumentsMatchResult matchResult, TypeReference argumentType, TypeReference parameterType, TypeReference[] inflatedTypes, ref int leftInflatedTypeCount) {

            // 如果实参为需要推导的类型，则无法根据此参数推导泛型参数的值。
            if (argumentType == null) {
                return;
            }

            // 如果发现属于当前成员的泛型形参，则推导类型。
            if (parameterType.memberType == MemberType.typeParameter && ((GenericTypeParameterReference)parameterType).genericDefinitionMember == matchResult.member) {
                var index = ((GenericTypeParameterReference)parameterType).index;
                if (inflatedTypes[index] == null) {
                    inflatedTypes[index] = argumentType;
                    leftInflatedTypeCount--;
                }
                return;
            }

            // 如果形参是包含泛型参数的参数，则递归推导。
            if (parameterType.genericArguments != null) {
                if (argumentType.underlyingType.getAllRequiredTypes().Contains(parameterType.underlyingType)) {
                    for (var i = 0; i < parameterType.genericArguments.Length; i++) {
                        tryInflateGenericParamter(matchResult, argumentType.genericArguments[i], parameterType.genericArguments[i], inflatedTypes, ref leftInflatedTypeCount);
                    }
                }
            }

        }

        /// <summary>
        /// 指示比较的两个参数哪个更好。
        /// </summary>
        private enum BetterResult {

            /// <summary>
            /// 都不更好。
            /// </summary>
            neither,

            /// <summary>
            /// 第一个参数更好。
            /// </summary>
            left,

            /// <summary>
            /// 第二个参数更好。
            /// </summary>
            right,

        }

        /// <summary>
        /// 比较两个重载并找出一个最好的结果。
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        private static BetterResult betterFunction(ArgumentsMatchResult left, ArgumentsMatchResult right, ResolvedArguments arguments) {

            // 记录比较的最终结果。
            BetterResult result = BetterResult.neither;

            // 存在实参的隐式转换更好。
            for (int i = 0; i < arguments.count; i++) {

                // 判断谁的类型转换更娇。
                var r = betterConversion(left.conversions[i], right.conversions[i]);

                // 两个都不是更好，此参数地位相同。
                if (r == BetterResult.neither) {
                    continue;
                }

                // 发现一个参数比另一个更好。
                if (result == BetterResult.neither) {
                    // 第 1 次发现，确定更好的结果。
                    result = r;
                } else if (r != result) {
                    // 第 2 次发现，但是和之前参数的结果不同。
                    return BetterResult.neither;
                }

            }

            // 如果根据参数已经比较出结果，则返回结果。如果参数完全相同，则两者都不是最好的。
            if (result != BetterResult.neither) {
                return result;
            }

            // 根据展开形式确定。
            if (left.type != right.type) {

                // 普通形式匹配更好。
                if (left.type == ArgumentsMatchType.applicableInNormalForm) {
                    return BetterResult.left;
                } else if (right.type == ArgumentsMatchType.applicableInNormalForm) {
                    return BetterResult.right;
                }

                // 缺省参数展开形式匹配更好。
                if (left.type == ArgumentsMatchType.applicableInOptionalExpandedForm) {
                    return BetterResult.left;
                } else if (right.type == ArgumentsMatchType.applicableInOptionalExpandedForm) {
                    return BetterResult.right;
                }

                // 可变参数展开形式匹配更好。
                if (left.type == ArgumentsMatchType.applicableInArgListExpandedForm) {
                    return BetterResult.left;
                } else if (right.type == ArgumentsMatchType.applicableInArgListExpandedForm) {
                    return BetterResult.right;
                }

                throw new Unreachable();
            }

            // 非泛型更好。
            if (left.member.genericParameters == null) {
                if (right.member.genericParameters != null) {
                    return BetterResult.left;
                }
            } else if (right.member.genericParameters == null) {
                return BetterResult.right;
            }

            // 都以展开形式匹配时，形参更多的好。
            if (left.type != ArgumentsMatchType.applicableInNormalForm) {
                if (left.parameters.Length > right.parameters.Length) {
                    return BetterResult.left;
                }
                if (left.parameters.Length < right.parameters.Length) {
                    return BetterResult.right;
                }
            }

            // 最后，两个方法都不是最好的。
            return BetterResult.neither;
        }

        /// <summary>
        /// 比较两个重载，判断谁的类型转换更好。
        /// </summary>
        /// <param name="leftConversion"></param>
        /// <param name="rightConversion"></param>
        /// <returns></returns>
        private static BetterResult betterConversion(ConversionType leftConversion, ConversionType rightConversion) {

            if (leftConversion == rightConversion) {
                return BetterResult.neither;
            }

            // 标识转换比隐式转换好。
            if (leftConversion == ConversionType.identity) {
                return BetterResult.left;
            }
            if (rightConversion == ConversionType.identity) {
                return BetterResult.right;
            }

            return BetterResult.neither;
        }

        private static void reportResolveMethodOverloadError(List<ArgumentsMatchResult> matchResults, Node srcNode) {

            Debug.Assert(matchResults.Count > 1);

            // 已知 matchResults 不符合要求，则向用户报告最合适的匹配项。

            matchResults.Sort((x, y) => {

                // 合法的更好。
                if (x.isValid != y.isValid) {
                    return x.isValid ? 1 : -1;
                }

                // 根据展开形式确定。
                if (x.type != y.type) {
                    return y.type - x.type;
                }

                // 更迟出现错误的好。
                if (y.badArgumentIndex != x.badArgumentIndex) {
                    return y.badArgumentIndex - x.badArgumentIndex;
                }

                // 形参更多的好。
                return y.parameters.Length - x.parameters.Length;
            });

            Compiler.error(ErrorCode.none, String.Format("无法确定此处是调用“{0}”还是“{1}”", matchResults[0].member.fullName, matchResults[1].member.fullName), srcNode);

        }

        private static void reportResolveMethodOverloadError(ArgumentsMatchResult result, ResolvedArguments arguments, Node srcNode) {

            switch (result.type) {
                case ArgumentsMatchType.badArgument:
                    var badArgument = arguments[result.badArgumentIndex];
                    Compiler.error(ErrorCode.none, String.Format(result.conversions[result.badArgumentIndex] == ConversionType.none ? "无法调用“{0}”；无法将参数 {1} 从类型“{2}”转换为“{3}”" : "无法调用“{0}”；无法将参数 {1} 从类型“{2}”隐式转换为“{3}”（存在一个显示转换，是否缺少显式转换?）", result.member.fullName, result.badArgumentIndex + 1, badArgument.resolvedValue.resolvedType.fullName, result.getParameterType(result.badArgumentIndex).fullName), badArgument.value);
                    break;
                case ArgumentsMatchType.tooManyArguments:
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”；调用的参数太多", result.member.fullName), arguments[result.badArgumentIndex].value);
                    break;
                case ArgumentsMatchType.missingArgument:
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”；缺少参数 {1}", result.member.fullName, result.badArgumentIndex + 1), srcNode);
                    break;
                case ArgumentsMatchType.namedArgumentNotFound:
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”；命名参数 {1} 无法匹配", result.member.fullName, result.badArgumentIndex + 1), arguments[result.badArgumentIndex].name);
                    break;
                case ArgumentsMatchType.dumpNamedArgument:
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”；命名参数 {1} 重复", result.member.fullName, result.badArgumentIndex + 1), arguments[result.badArgumentIndex].name);
                    break;
                case ArgumentsMatchType.nameUsedForPositional:
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”；命名参数 {1} 和位置参数冲突", result.member.fullName, result.badArgumentIndex + 1), arguments[result.badArgumentIndex].name);
                    break;
                case ArgumentsMatchType.genericTypeParameterUnknown:
                    Compiler.error(ErrorCode.none, String.Format("无法调用“{0}”；无法推导泛型形参 {1} 的类型", result.member.fullName, result.badArgumentIndex + 1), srcNode);
                    break;
                default:
                    throw new Unreachable();
            }

        }

        private static int resolveOperatorOverload(ResolveContext context, Expression left, string opName, Expression right, ResolvedArguments arguments, List<ArgumentsMatchResult> matchResults) {

            arguments.positionalArgumentsCount = 1;
            arguments.ensureCapicity();
            arguments[0] = new FuncCallExpression.Argument() {
                resolvedValue = right
            };

            var members = left.resolvedType.getAllMembers(opName);
            if (members == null) {
                return -1;
            }

            // 找出所有匹配项中最好的重载。
            return resolveMethodOverload(context, members, arguments, matchResults);

        }

    }

}
